#pragma once

#include <wx/event.h>
#include <wx/app.h>
#include <wx/thread.h>

// BEGIN_DECLARE_EVENT_TYPES()
// DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_FILTER_EVENT, -1)
// END_DECLARE_EVENT_TYPES()

DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_FILTER_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGSRC_FILTER_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_PROPERTIES_EVENT, -1);

// INI download event
DECLARE_LOCAL_EVENT_TYPE(wxEVT_INI_DOWNLOAD_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_INI_DOWNLOADING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_INI_DOWNLOAD_COMPLETED_EVENT, -1);

// Packages download event
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_DOWNLOAD_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_DOWNLOADING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_DOWNLOAD_COMPLETED_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_DOWNLOAD_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_DOWNLOADING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_DOWNLOAD_COMPLETED_EVENT, -1);

// Packages removal event
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_REMOVE_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_REMOVING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_REMOVE_COMPLETED_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_REMOVE_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_REMOVING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_REMOVE_COMPLETED_EVENT, -1);
// Packages installation event
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_INSTALL_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_INSTALLING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKG_INSTALL_COMPLETED_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_INSTALL_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_INSTALLING_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_INSTALL_COMPLETED_EVENT, -1);

// scrips running events
DECLARE_LOCAL_EVENT_TYPE(wxEVT_RUN_PREREMOVE_SCRIPT_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_RUN_POSTINSTALL_SCRIPT_EVENT, -1);

// maintain events
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_MAINTIAN_BEGIN_EVENT, -1);
DECLARE_LOCAL_EVENT_TYPE(wxEVT_PKGS_MAINTIAN_COMPLETED_EVENT, -1);

WX_DEFINE_ARRAY(wxWindow*, wxEvtHandlerPtrArray);

WX_DECLARE_HASH_MAP(wxEventType, wxEvtHandlerPtrArray, wxIntegerHash, wxIntegerEqual, EventHash);

/**
 * Process custom wxCommandEvent
 */
class EventCenter {
public:
	static EventCenter& get() {
		return self;
	}
	
	static void registerr(wxEventType type, wxWindow* handler) {
		self.event_hash[type].Add(handler);
	}
	static void unregister(wxEventType type, wxWindow* handler) {
		for (EventHash::iterator it=self.event_hash.begin(); it!=self.event_hash.end(); it++) {
			if ( type==it->first ) {
				it->second.Remove(handler);
				
				break;
			}
		}
	}
	static void unregister(wxWindow* handler) {
		for (EventHash::iterator it=self.event_hash.begin(); it!=self.event_hash.end(); it++) {
			for (int i=0; i<it->second.GetCount(); i++) {
				if (handler==it->second[i]) {
					it->second.RemoveAt(i);
					break;
				}
			}
		}
	}
	
	static bool post(wxEventType type, const wxString& data) {
		wxCommandEvent event(type);
		event.SetString(data);
		
		_post(type, event);
	}
	
	static bool post(wxEventType type, int data) {
		wxCommandEvent event(type);
		event.SetInt(data);
		
		_post(type, event);
	}
	
	static bool post(wxEventType type, const wxString& data1, int data2) {
		wxCommandEvent event(type);
		event.SetString(data1);
		event.SetInt(data2);
		
		_post(type, event);
	}
	
	static bool post(wxEventType type) {
		wxCommandEvent event(type);
		
		_post(type, event);
	}
	
	static bool _post(wxEventType type, wxCommandEvent& event) {
		const wxEvtHandlerPtrArray& handler_array = self.event_hash[type];
		
		for (int i=0; i<handler_array.GetCount(); i++) {
			wxWindow* handler = handler_array[i];
			
			if (NULL==handler) {
				continue;
			}
			
			event.SetId(handler->GetId());
			event.SetEventObject(handler);
			
			wxPostEvent(handler, event);
			
			// just give more time to message system
		    // wxTheApp->Yield();
		    wxThread::Yield(); // Sleep(0);
		}
	}
	
	virtual ~EventCenter() {}
	
protected:
	static EventCenter self;
	
	EventHash event_hash;
	
	EventCenter() {
		
	}
	// static wxEvtHandlerPtrArray 
};
